﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI.WebControls;
using System.Web.UI;
using System.Reflection;
using Bingosoft.Common.Logging;
using Bingosoft.Data;
using Newtonsoft.Json;
using System.Data;
using HHMMS.Core.Common;
using Newtonsoft.Json.Converters;

namespace System
{
    /// <summary>
    /// 通用扩展静态方法。
    /// </summary>
    public static class CommonExtensions
    {
        private const BindingFlags PublicInstancePropertyBindingFlags = BindingFlags.CreateInstance
           | BindingFlags.Instance         //实例
           | BindingFlags.Public           //公有
           | BindingFlags.GetProperty      //可得属性
           | BindingFlags.IgnoreCase;      //忽略大小写

        private static readonly JsonSerializerSettings _jsonSerializerSettings = new JsonSerializerSettings
        {
            Converters
                = new JsonConverter[]
                                {
                                    new JavaScriptDateTimeConverter()
                                }
        };

        #region Object对象扩展
        /// <summary>
        /// 将指定对象序列化为JSON字符串。
        /// </summary>
        /// <param name="o"></param>
        /// <returns></returns>
        public static string ToJson(this object o)
        {
            return JsonConvert.SerializeObject(o, Formatting.None, _jsonSerializerSettings);
        }

        /// <summary>
        /// 将JSON格式的字符串反序列化为指定对象。
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="s"></param>
        /// <returns></returns>
        public static T ParseJson<T>(this string s)
        {
            return JsonConvert.DeserializeObject<T>(s, _jsonSerializerSettings);
        }

        /// <summary>
        /// 将JSON格式的字符串反序列化为指定类型的对象。
        /// </summary>
        /// <param name="s"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        public static object ParseJson(this string s, Type type)
        {
            return JsonConvert.DeserializeObject(s, type);
        }

        /// <summary>
        /// 获取某个对象中某个属性的值。
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <param name="propertyName"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static T GetValue<T>(this Object obj, string propertyName, T defaultValue)
        {
            if (obj != null)
            {
                var p = obj.GetType().GetProperty(propertyName, PublicInstancePropertyBindingFlags);
                if (p != null)
                    return (p.GetValue(obj, null) + "").ConvertTo<T>(defaultValue);
            }
            return defaultValue;
        }

        /// <summary>
        /// 执行指定的方法并将捕的获异常记录到异常日志中，返回一个布尔值指定是否有异常。
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="method">待执行的委托或方法</param>
        /// <param name="errMsg">异常信息</param>
        /// <returns></returns>
        public static bool ExecuteAction(this Object obj, Action method, string errMsg = null)
        {
            bool succ = true;
            try
            {
                method();
            }
            catch (Exception ex)
            {
                succ = false;
                if (string.IsNullOrEmpty(errMsg))
                {
                    errMsg = ex.Message;
                }
                if (HttpContext.Current != null
                    && HttpContext.Current.User != null
                    && HttpContext.Current.User.Identity != null
                    && HttpContext.Current.User.Identity.IsAuthenticated)
                {
                    errMsg = "操作人：" + HttpContext.Current.User.Identity.Name + "。异常：" + errMsg;
                }

                //记录到日志文件
                ILog log = LogManager.GetLogger(obj.GetType());
                log.Error(errMsg, ex);

                //记录日志到数据量
                //TOOD
            }
            return succ;
        }

        /// <summary>
        /// 用指定的分隔符连接字符串数组并返回。
        /// </summary>
        /// <param name="array"></param>
        /// <param name="splitChar">分隔符字符</param>
        /// <returns></returns>
        public static string Join(this string[] array, string splitChar)
        {
            string str = string.Empty;
            foreach (string s in array)
            {
                str = string.Format("{0}{1}{2}", str, string.IsNullOrEmpty(str) ? "" : splitChar, str);
            }
            return str;
        }
        #endregion

        #region String对象扩展
        public static bool In<T>(this T value, params T[] list)
        {
            return list.Contains(value);
        }

        public static bool Contains<T>(this T[] arr, T val)
        {
            return arr.ToList<T>().Contains(val);
        }

        public static string EscapeComma(this string text)
        {
            if (string.IsNullOrEmpty(text))
            {
                return text;
            }

            return text
                .Replace("\\", "\\\\")
                .Replace("'", "\\'")
                .Replace("\"", "\\\"")
                .Replace("\r\n", " ")
                .Replace("\n", " ");
        }
        /// <summary>
        /// 把字符串转换成指定类型
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="text"></param> 
        /// <returns></returns>
        public static T ConvertTo<T>(this string text)
        {
            return ConvertTo<T>(text, default(T));
        }

        /// <summary>
        /// 把字符串转换成指定类型
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="text"></param>
        /// <param name="defaultValue">默认值</param>
        /// <returns></returns>
        public static T ConvertTo<T>(this string text, T defaultValue)
        {
            if (string.IsNullOrEmpty(text))
                return defaultValue;

            try
            {
               return  Bingosoft.Data.Convert.Converter.Convert<T>(text);
            }
            catch
            {
                return defaultValue;
            }
        }
        #endregion

        #region Request对象扩展
        /// <summary>
        /// 获取当前应用程序的根路径，该路径包括域名以及端口。
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public static string GetContextPath(this HttpRequest request)
        {
            return request.Url.Scheme + "://"
                + request.Url.Host
                + (request.Url.Port.Equals(80) ? "" : (":" + request.Url.Port))
                + ("/".Equals(request.ApplicationPath) ? "" : request.ApplicationPath);
        }

        /// <summary>
        /// 从Url中获取指定名称的查询参数并转换为指定的类型。
        /// </summary>
        /// <typeparam name="T">参数类型</typeparam>
        /// <param name="request"></param>
        /// <param name="key">参数名称</param>
        /// <returns></returns>
        public static T GetQuery<T>(this System.Web.HttpRequest request, string key)
        {
            if (request[key] != null)
            {
                return request.QueryString[key].ConvertTo<T>();
            }
            return default(T);
        }

        /// <summary>
        /// 从Url中获取指定名称的查询参数并转换为指定的类型，并指定无该参数或者参数类型转换失败时返回的默认值。
        /// </summary>
        /// <typeparam name="T">参数类型</typeparam>
        /// <param name="request"></param>
        /// <param name="key">参数名称</param>
        /// <param name="defaultValue">参数默认值</param>
        /// <returns></returns>
        public static T GetQuery<T>(this System.Web.HttpRequest request, string key, T defaultValue)
        {
            if (request[key] != null)
            {
                return request.QueryString[key].ConvertTo<T>(defaultValue);
            }
            return defaultValue;
        }
        #endregion

        #region Control对象扩展
        /// <summary>
        /// 将下拉框绑定到指定数据源。
        /// </summary>
        /// <param name="dropDownList"></param>
        /// <param name="dataSource"></param>
        /// <param name="dataTextField"></param>
        /// <param name="dataValueField"></param>
        /// <param name="addEmptyItem"></param>
        /// <param name="selectedValue"></param>
        public static void DataBind(this DropDownList dropDownList,
            object dataSource, string dataTextField, string dataValueField, bool addEmptyItem = true, string selectedValue = "")
        {
            dropDownList.Items.Clear();
            if (dataSource != null)
            {
                dropDownList.DataSource = dataSource;
                dropDownList.DataTextField = dataTextField;
                dropDownList.DataValueField = dataValueField;
                dropDownList.DataBind();
            }
            if (addEmptyItem)
            {
                dropDownList.Items.Insert(0, new ListItem("--请选择--", ""));
            }
            if (dropDownList.Items.FindByValue(selectedValue) != null)
            {
                dropDownList.SelectedValue = selectedValue;
            }
        }

        /// <summary>
        /// 查找控件
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="control"></param>
        /// <param name="id"></param>
        /// <returns></returns>
        public static T FindControl<T>(this Control control, string id) where T : class
        {
            object obj = control.FindControl(id);
            return obj as T;
        }

        /// <summary>
        /// 查找控件
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="control"></param>
        /// <param name="id"></param>
        /// <param name="delegateWhenFound">当查找成功时调用</param>
        /// <returns></returns>
        public static T FindControl<T>(this Control control, string id, Action<T> delegateWhenFound) where T : class
        {
            object obj = control.FindControl(id);
            T c = obj as T;
            if (c != null)
            {
                delegateWhenFound(c);
            }
            return c;
        }
        #endregion

        #region GridView对象扩展
        /// <summary>
        /// 将GridView数据导出为Excel。
        /// </summary>
        /// <param name="gridView"></param>
        /// <param name="fileName">文件名，如"temp.xls"</param>
        /// <param name="exportAll">是否导出所有，默认只导出当前页</param>
        public static void SaveAsXls(this GridView gridView, string fileName, bool? exportAll = false, params int[] hideColIndex)
        {
            Util.ExportGridView(gridView, fileName, exportAll, hideColIndex);
        }

        /// <summary>
        /// 将GridView数据导出为Excel，并指定是否导出所有数据、是否隐藏第一列以及最后一列。
        /// </summary>
        /// <param name="gridView"></param>
        /// <param name="fileName"></param>
        /// <param name="exportAll"></param>
        /// <param name="hideFirstCol"></param>
        /// <param name="hideLastCol"></param>
        public static void SaveAsXls(this GridView gridView, string fileName, bool? exportAll = false, bool? hideFirstCol = false, bool? hideLastCol = true)
        {
            Util.ExportGridView(gridView, fileName, exportAll, hideFirstCol.HasValue && hideFirstCol.Value ? 0 : -1,
                hideLastCol.HasValue && hideLastCol.Value ? gridView.Columns.Count - 1 : -1);
        }
        #endregion

        /// <summary>
        /// 获取当前登录用户是否拥有指定的角色。
        /// </summary>
        /// <param name="roleID"></param>
        /// <param name="deptID"></param>
        /// <returns></returns>
        public static bool HasRole(this Bingosoft.Security.Principal.IUser user, string roleID)
        {
            return user.Roles.Any(item => { return item.Id.Equals(roleID, StringComparison.OrdinalIgnoreCase); });
        }
    }
}